---
id: rule-tester
sidebar_label: rule-tester
---

import CodeBlock from '@theme/CodeBlock';

# `@typescript-eslint/rule-tester`

<PackageLink packageName="rule-tester" scope="@typescript-eslint" />

> A utility for testing ESLint rules

This is a fork of ESLint's built-in `RuleTester` to provide some better types and additional features for testing TypeScript rules.

## Usage

For non-type-aware rules you can test them as follows:

```ts
import { RuleTester } from '@typescript-eslint/rule-tester';
import rule from '../src/rules/my-rule.ts';

const ruleTester = new RuleTester();

ruleTester.run('my-rule', rule, {
  valid: [
    // valid tests can be a raw string,
    'const x = 1;',
    // or they can be an object
    {
      code: 'const y = 2;',
      options: [{ ruleOption: true }],
    },

    // you can enable JSX parsing by passing parserOptions.ecmaFeatures.jsx = true
    {
      code: 'const z = <div />;',
      languageOptions: {
        parserOptions: {
          ecmaFeatures: {
            jsx: true,
          },
        },
      },
    },
  ],
  invalid: [
    // invalid tests must always be an object
    {
      code: 'const a = 1;',
      // invalid tests must always specify the expected errors
      errors: [
        {
          messageId: 'ruleMessage',
          // If applicable - it's recommended that you also assert the data in
          // addition to the messageId so that you can ensure the correct message
          // is generated
          data: {
            placeholder1: 'a',
          },
        },
      ],
    },

    // fixers can be tested using the output parameter
    {
      code: 'const b = 1;',
      output: 'const c = 1;',
      errors: [
        /* ... */
      ],
    },
    // passing `output = null` will enforce the code is NOT changed
    {
      code: 'const c = 1;',
      output: null,
      errors: [
        /* ... */
      ],
    },
    // Multi-pass fixes can be tested using the array form of output.
    // Note: this is unique to typescript-eslint, and doesn't exist in ESLint core.
    {
      code: 'const d = 1;',
      output: ['const e = 1;', 'const f = 1;'],
      errors: [
        /* ... */
      ],
    },

    // suggestions can be tested via errors
    {
      code: 'const d = 1;',
      output: null,
      errors: [
        {
          messageId: 'suggestionError',
          suggestions: [
            {
              messageId: 'suggestionOne',
              output: 'const e = 1;',
            },
          ],
        },
      ],
    },
    // passing `suggestions = null` will enforce there are NO suggestions
    {
      code: 'const d = 1;',
      output: null,
      errors: [
        {
          messageId: 'noSuggestionError',
          suggestions: null,
        },
      ],
    },
  ],
});
```

### Type-Aware Testing

Type-aware rules can be tested in almost exactly the same way as regular code, using `parserOptions.projectService`.
Most rule tests specify `parserOptions.allowDefaultProject: ["*.ts*"]` to enable type checking on all test files.

You can then test your rule by providing the type-aware config:

```ts
const ruleTester = new RuleTester({
  // Added lines start
  languageOptions: {
    parserOptions: {
      projectService: {
        allowDefaultProject: ['*.ts*'],
      },
      tsconfigRootDir: './path/to/your/folder/fixture',
    },
  },
  // Added lines end
});
```

With that config the parser will automatically run in type-aware mode and you can write tests just like before.

When not specified with a `filename` option, `RuleTester` uses the following test file names:

- `file.ts`: by default
- `react.tsx`: if `parserOptions.ecmaFeatures.jsx` is enabled

### Test Dependency Constraints

Sometimes it's desirable to test your rule against multiple versions of a dependency to ensure backwards and forwards compatibility.
With backwards-compatibility testing there comes a complication in that some tests may not be compatible with an older version of a dependency.
For example - if you're testing against an older version of TypeScript, certain features might cause a parser error!

import DependencyConstraint from '!!raw-loader!../../packages/rule-tester/src/types/DependencyConstraint.ts';

<CodeBlock language="ts">{DependencyConstraint}</CodeBlock>

The `RuleTester` allows you to apply dependency constraints at either an individual test or constructor level.

```ts
const ruleTester = new RuleTester({
  // Added lines start
  dependencyConstraints: {
    // none of the tests will run unless `my-dependency` matches the semver range `>=1.2.3`
    'my-dependency': '1.2.3',
    // you can also provide granular semver ranges
    'my-granular-dep': {
      // none of the tests will run unless `my-granular-dep` matches the semver range `~3.2.1`
      range: '~3.2.1',
    },
  },
  // Added lines end
});

ruleTester.run('my-rule', rule, {
  valid: [
    {
      code: 'const y = 2;',
      // Added lines start
      dependencyConstraints: {
        // this test won't run unless BOTH dependencies match the given ranges
        first: '1.2.3',
        second: '3.2.1',
      },
      // Added lines end
    },
  ],
  invalid: [
    /* ... */
  ],
});
```

All dependencies provided in the `dependencyConstraints` object must match their given ranges in order for a test to not be skipped.

### With Specific Frameworks

ESLint's `RuleTester` relies on some global hooks for tests.
If they aren't available globally, your tests will fail with an error like:

> ```plaintext
> Error: Missing definition for `afterAll` - you must set one using `RuleTester.afterAll` or there must be one defined globally as `afterAll`.
> ```

:::tip
Be sure to set `RuleTester`'s static properties _before_ calling `new RuleTester(...)` for the first time.
:::

#### Mocha

Consider setting up `RuleTester`'s static properties in a [`mochaGlobalSetup` fixture](https://mochajs.org/#global-setup-fixtures):

```ts
import * as mocha from 'mocha';
import { RuleTester } from '@typescript-eslint/rule-tester';

RuleTester.afterAll = mocha.after;
```

#### Node.js (`node:test`)

Consider setting up `RuleTester`'s static properties in a preloaded module using the [`--import`](https://nodejs.org/api/cli.html#--importmodule) or [`--require`](https://nodejs.org/api/cli.html#-r---require-module) flag:

```ts
// setup.js
import * as test from 'node:test';
import { RuleTester } from '@typescript-eslint/rule-tester';

RuleTester.afterAll = test.after;
RuleTester.describe = test.describe;
RuleTester.it = test.it;
RuleTester.itOnly = test.it.only;
```

Tests can then be [run from the command line](https://nodejs.org/api/test.html#running-tests-from-the-command-line) like so:

```sh
node --import setup.js --test
```

#### Vitest

Consider setting up `RuleTester`'s static properties in a [`setupFiles` script](https://vitest.dev/config/#setupfiles):

```ts
import * as vitest from 'vitest';
import { RuleTester } from '@typescript-eslint/rule-tester';

RuleTester.afterAll = vitest.afterAll;

// If you are not using vitest with globals: true (https://vitest.dev/config/#globals):
RuleTester.it = vitest.it;
RuleTester.itOnly = vitest.it.only;
RuleTester.describe = vitest.describe;
```

#### Other Frameworks

In general, `RuleTester` can support any test framework that exposes hooks for running code before or after rules.
From `RuleTester`'s [Static Properties](#static-properties), assign any of the following that the running test framework supports.

- `afterAll`
- `describe`
- `it`
- `itOnly`

I.e.:

```ts
import * as test from '...';
import { RuleTester } from '@typescript-eslint/rule-tester';

RuleTester.afterAll = test.after;
RuleTester.describe = test.describe;
RuleTester.it = test.it;
RuleTester.itOnly = test.it.only;
```

## Options

### `RuleTester` constructor options

import RuleTesterConfig from '!!raw-loader!../../packages/rule-tester/src/types/RuleTesterConfig.ts';

<CodeBlock language="ts">{RuleTesterConfig}</CodeBlock>

### Valid test case options

import ValidTestCase from '!!raw-loader!../../packages/rule-tester/src/types/ValidTestCase.ts';

<CodeBlock language="ts">{ValidTestCase}</CodeBlock>

### Invalid test case options

import InvalidTestCase from '!!raw-loader!../../packages/rule-tester/src/types/InvalidTestCase.ts';

<CodeBlock language="ts">{InvalidTestCase}</CodeBlock>

## Static Properties

Each of the following properties may be assigned to as static members of the `RuleTester` class.

For example, to assign `afterAll`:

```ts
import { RuleTester } from '@typescript-eslint/rule-tester';

RuleTester.afterAll = () => {
  // ...
};
```

### `afterAll`

Runs after all the tests in this file have completed.

### `describe`

Creates a test grouping.

### `describeSkip`

Skips running the tests inside this `describe`.

### `it`

Creates a test closure.

### `itOnly`

Skips all other tests in the current file.

### `itSkip`

Skips running this test.
